#include "server.h"

Server::Server()
{
    //READ: Iinicializar la bandera en false, enlazar o conectar el evento o seal
    // de newConnection que genere una instancia de esta clase y que la reciba y procese
    // esta misma instancia por el SLOT newConnection ..
    // Limpiar la lista de conexiones
    // Hacer que el apuntador al TextEdit(Log) sea nulo
    this->server_started = false;
    connect(this, SIGNAL(newConnection()), this, SLOT(newConnection()));
    this->Lista_Conexiones.clear();
    this->log = 0;
    this->test=0;
    this->spinA=0;
    this->sliderA=0;
    this->spinB=0;
    this->sliderB=0;
    this->spinC=0;
    this->sliderC=0;
    //Señal y slot de comenzar y parar procesos
    //ProductoA
    ProdA = new producto();
    ProdA->setMax(40);
    connect(ProdA,SIGNAL(crearProducto(int)),this,SLOT(AlCrearProductosA(int)),Qt::QueuedConnection);
    ProdA->start();
    //ProductoB
    ProdB = new producto();
    ProdB->setMax(50);
    connect(ProdB,SIGNAL(crearProducto(int)),this,SLOT(AlCrearProductosB(int)),Qt::QueuedConnection);
    ProdB->start();

    //ProductoC
    ProdC = new producto(this);
    ProdC->setMax(60);
    connect(ProdC,SIGNAL(crearProducto(int)),this,SLOT(AlCrearProductosC(int)),Qt::QueuedConnection);
    ProdC->start();

}

void Server::AlCrearProductosA(int num1)
{
    this->sliderA->setValue(num1);
    this->spinA->setValue(num1);
}

void Server::AlCrearProductosB(int num2)
{
    this->sliderB->setValue(num2);
    this->spinB->setValue(num2);
}

void Server::AlCrearProductosC(int num3)
{
    this->sliderC->setValue(num3);
    this->spinC->setValue(num3);
}

Server::~Server()
{
    //READ: Simplemente llamar al metodo STOP que hace toda la limpieza
    this->stop();
    ProdA->stop();
    ProdB->stop();
    ProdC->stop();
}

void Server::start(int port)
{
    //READ: Bueno iniciar el server siempre y cuando NO se haya iniciado previamente
    // para eso se revisa la bandera. Luego ejecutamos el metodo LISTEN para escuchar
    // en el puerto que recibe de parametro, en caso que no pueda escuchar en ese
    // puerto porque por ejemplo puede que ya este ocupado entonces, mostrar un mensaje
    // y dejar en false la bandera.
    // Si logra arranca, entonces colocar la bandera en True, instancia la nickList
    // Limpia la lista de conexiones y muestra un mensaje en el LOG.

    if (this->server_started==false)
    {
        if (listen(QHostAddress::Any, port))
        {
           this->server_started = true;
           this->nickList = new QStringList();
           this->Lista_Conexiones.clear();
           this->log->append(tr("Servidor iniciado en puerto :%1 ").arg(port));
        }
        else
        {
            this->server_started = false;
            this->log->append(tr("Servidor no se pudo iniciar :%1 ").arg(this->errorString()));
        }
    }

}
void Server::stop()
{
    if (this->server_started)
    {

      this->server_started = false;
      delete this->nickList;
      // Limpiar la lista de conexiones

       while (!this->Lista_Conexiones.isEmpty())
         {
            // this->Lista_Conexiones.at(0)->disconnect(); //Desconectar la conexion

             Connection *cTemp= this->Lista_Conexiones.takeFirst();  // Libera el apuntador
             cTemp->sendMessage("SERVERSTOP:\n\r");
             delete cTemp;
         }
        //Cerrar el socket del server
        this->close();
        this->log->append(tr("Servidor detenido!!! "));
    }

}
bool Server::getStatus()
{
    return this->server_started;
}
void Server::newConnection() {
        // Cuando se crea la conexion la enlazo agregandola a lista de conexiones
        Connection *con = new Connection(nextPendingConnection());
         // Agregarla a la lista de conexiones
        this->Lista_Conexiones.push_back(con);
        // Decirle a la conexion en que posicion de la lista la agregaron
        con->indice_lista_conexion = this->Lista_Conexiones.count()-1;

        connect(con, SIGNAL(newMessage(Connection*,QString)), this, SLOT(procesarMensaje(Connection*,QString)));
       // connect(this, SIGNAL(newMessage(QString)), con, SLOT(sendMessage(QString)));
        connect(con, SIGNAL(connected(Connection*, QString)), this, SLOT(connected(Connection*, QString)));
        connect(con, SIGNAL(disconnected(Connection*, QString)), this , SLOT(disconnected(Connection*, QString)));

        this->log->append("Nueva conexion..." + con->socket->peerAddress().toString());


}
void Server::connected(Connection* con, QString nick) {
        //Enviar los Nicks ya existentes
        //TODO: Se deberia validar un nick repetido
        con->sendNicks(this->nickList);
        this->log->append("Nicks enviados al resto...");
        nickList->push_back(nick);
        con->nick=nick;
        // Enviar un mensaje a todos de este nuevo Nick
        this->sendMessage("NEWNICK:"+nick + "\n\r");
        this->log->append(nick + " [" + con->socket->peerAddress().toString() + "] connected");


}

void Server::disconnected(Connection* con, QString nick) {
        //con->deleteLater();
        int index = nickList->indexOf(nick);
        nickList->removeAt(index);
        // Remover de la lista de conexiones.
        this->log->append(nick + " disconnected");

        this->Lista_Conexiones.at(con->indice_lista_conexion)->socket->close();

        //Avisar al resto que se desconecto
        this->sendMessage("OLDNICK:"+nick + "\n\r");

}
void Server::sendMessage(QString mensaje)
{ // Recorrer la lista de conexiones y enviar
   int i=0;
    while (i<this->Lista_Conexiones.count())
   {
    //TODO: Deberiamos validar el estado de la conexion
        // Para no tratar de enviar en Conexiones cerradas
        // O en el disconnect asegurarse de poner en estado no valida
        // la conexion. Porque sino se pierde el indice.
        if(this->Lista_Conexiones.at(i)->socket->isValid())
           this->Lista_Conexiones.at(i)->sendMessage(mensaje);
    i++;
   }


}
void Server::procesarMensaje(Connection *con, QString mensaje)
{
    int i=0;
    while (i<this->Lista_Conexiones.count())
   {
        // Enviar al resto lo que recibimos de con, inclusive al mismo (ECHO)
        if(this->Lista_Conexiones.at(i)->socket->isValid())
        {
            this->log->append(con->nick+">>Enviando:(" +this->Lista_Conexiones.at(i)->nick+"):" + mensaje);
            this->Lista_Conexiones.at(i)->sendMessage(mensaje);
            this->test->append(mensaje);
            if(mensaje.startsWith("productoA"))
            {
                this->test->append("paso un a");
                if(ProdA->getProducto()>0){
                    ProdA->consumirProducto();
                    this->spinA->setValue(ProdA->getProducto());
                    this->sliderA->setValue(ProdA->getProducto());
                }
                if(ProdA->getProducto()==0)
                    ProdA->start();
            } else if (mensaje.startsWith("productoB")){
                this->test->append("paso un b");
                if(ProdB->getProducto()>0){
                    ProdB->consumirProducto();
                    this->spinB->setValue(ProdB->getProducto());
                    this->sliderB->setValue(ProdB->getProducto());
                }
                if(ProdB->getProducto()==10)
                    ProdB->start();

            } else if (mensaje.startsWith("productoC")){
                this->test->append("paso un c");
                if(ProdC->getProducto()>0){
                    ProdC->consumirProducto();
                    this->spinC->setValue(ProdC->getProducto());
                    this->sliderC->setValue(ProdC->getProducto());
                }
                if(ProdC->getProducto()==20)
                    ProdC->start();

            }

    i++;
        }

   }
}
